package com.wechat.utils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Writer;
import java.net.ConnectException;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.ResourceBundle;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.servlet.http.HttpServletRequest;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
import com.wechat.model.response.Article;
import com.wechat.model.response.NewsMessage;
import com.wechat.model.response.TextMessage;
import com.wechat.model.wechat.AccessToken;
import com.wechat.model.wechat.JsapiTicket;
import com.wechat.model.wechat.Menu;

public class WechatMessageUtils {
	/**
	 * 返回类型：文本
	 */
	public static final String RESP_MESSAGE_TYPE_TEXT = "text";
	/**
	 * 返回类型：音乐
	 */
	public static final String RESP_MEAASGE_TYPE_MUSIC = "music";
	/**
	 * 返回类型：图文
	 */
	public static final String RESP_MESSAGE_TYPE_NEWS = "news";
	/**
	 * 请求类型：文本
	 */
	public static final String REQ_MESSAGE_TYPE_TEXT = "text";
	/**
	 * 请求类型：图片
	 */
	public static final String REQ_MESSAGE_TYPE_IMAGE = "image";
	/**
	 * 请求类型：链接
	 */
	public static final String REQ_MESSAGE_TYPE_LINK = "link";
	/**
	 * 请求消息类型：地理位置
	 */
	public static final String REQ_MESSAGE_TYPE_LOCATION = "location";

	/**
	 * 请求消息类型：音频
	 */
	public static final String REQ_MESSAGE_TYPE_VOICE = "voice";

	/**
	 * 请求消息类型：推送
	 */
	public static final String REQ_MESSAGE_TYPE_EVENT = "event";
	/**
	 * 事件类型：CLICK(自定义菜单点击事件)
	 */
	public static final String EVENT_TYPE_CLICK = "CLICK";
	/**
	 * 事件类型：view(自定义菜单跳转URL事件)
	 */
	public static final String EVENT_TYPE_VIEW = "view";
	/**
	 * 事件类型：subscribe(订阅)
	 */
	public static final String EVENT_TYPE_SUBSCRIBE = "subscribe";
	/**
	 * 事件类型：unsubscribe(取消订阅)
	 */
	public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";
	/**
	 * 事件类型:scan(扫描带参二维码)
	 */
	public static final String EVENT_TYPE_SCAN = "SCAN";
	/**
	 * AppID(应用ID)
	 */
	public static String APPID = null;
	/**
	 * AppSecret(应用密钥)
	 */
	public static String APPSECRET = null;
	static {
		ResourceBundle bundle = ResourceBundle.getBundle("config.wechatapp");
		APPID = bundle.getString("appid");
		APPSECRET = bundle.getString("appsecret");
	}
	/**
	 * 请求方式GET
	 */
	public static final String METHODGET = "GET";
	/**
	 * 请求方式POST
	 */
	public static final String METHODPOST = "POST";
	// 获取access_token值
	public static final String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPOLDID&secret=APPOLDSECRET";

	/**
	 * 发送https请求并获取结果
	 * 
	 * @param requestUrl
	 *            请求的链接
	 * @param methodType
	 *            请求方法类型（get、post）
	 * @param outMessage
	 *            提交值
	 * @return
	 */
	public static JSONObject httpsRequest(String requestUrl, String methodType, String outMessage) {

		JSONObject jsonObject = null;
		StringBuffer buffer = new StringBuffer();
		try {
			// 创建SSLContext对象，并使用我们指定的信任管理器初始化
			TrustManager[] tm = { new MyX509TrustManager() };
			SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
			sslContext.init(null, tm, new java.security.SecureRandom());
			// 从上述SSLContext对象中得到SSLSocketFactory对象
			SSLSocketFactory ssf = sslContext.getSocketFactory();

			URL url = new URL(requestUrl);
			HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
			httpUrlConn.setSSLSocketFactory(ssf);

			httpUrlConn.setDoOutput(true);
			httpUrlConn.setDoInput(true);
			httpUrlConn.setUseCaches(false);
			// 设置请求方式（GET/POST）
			httpUrlConn.setRequestMethod(methodType);
			if ("GET".equalsIgnoreCase(methodType)) {
				System.out.println("methodType:" + methodType);
				httpUrlConn.connect();
			}
			// 当有数据需要提交时
			if (null != outMessage) {
				OutputStream outputStream = httpUrlConn.getOutputStream();
				// 注意编码格式，防止中文乱码
				outputStream.write(outMessage.getBytes("UTF-8"));
				outputStream.close();
			}
			// 将返回的输入流转换成字符串
			InputStream inputStream = httpUrlConn.getInputStream();
			InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
			BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
			String str = null;
			while ((str = bufferedReader.readLine()) != null) {
				buffer.append(str);
			}
			bufferedReader.close();
			inputStreamReader.close();
			// 释放资源
			inputStream.close();
			inputStream = null;
			httpUrlConn.disconnect();
			jsonObject = JSONObject.parseObject(buffer.toString());
		} catch (ConnectException ce) {
		} catch (Exception e) {
		}
		return jsonObject;
	}

	/**
	 * 解析微信发来的请求(xml)
	 * @param request
	 * @return
	 * @throws IOException
	 * @throws DocumentException
	 */
	@SuppressWarnings("unchecked")
	public static Map<String, String> parseXml(HttpServletRequest request) throws IOException, DocumentException {
		Map<String, String> map = new HashMap<String, String>();
		// 从request中获取输入流
		InputStream input = request.getInputStream();
		SAXReader reader = new SAXReader();
		Document document = reader.read(input);
		Element element = document.getRootElement();
		List<Element> list = element.elements();
		// 遍历所有子节点
		for (Element e : list) {
			map.put(e.getName(), e.getText());
		}
		// 释放资源
		input.close();
		input = null;
		return map;
	}
	/**
	 * 文本消息对象转换成xml
	 * @param textMessage 文本消息对象
	 * @return xml
	 */
	public static String textMessageToXml(TextMessage textMessage) {
		xstream.alias("xml", textMessage.getClass());
		return xstream.toXML(textMessage);
	}
	/**
	 * 图文消息对象转换成xml
	 * @param newsMessage 图文消息对象
	 * @return xml
	 */
	public static String newsMessageToXml(NewsMessage newsMessage) {
		xstream.alias("xml", newsMessage.getClass());
		xstream.alias("item", new Article().getClass());
		return xstream.toXML(newsMessage);
	}
	/**
	 * 扩展xstream，使其支持CDATA块 所有xml文本中的内容都会被编辑器解析，只有CDATA中的文本会被编辑器忽略
	 * @date 2015-07-13
	 */
	private static XStream xstream = new XStream(new XppDriver() {
		public HierarchicalStreamWriter createWriter(Writer out) {
			return new PrettyPrintWriter(out) {
				// 对所有xml节点的转换都增加CDATA标记
				boolean cdata = true;
				public void startNode(String name, @SuppressWarnings("rawtypes") Class clazz) {
					super.startNode(name, clazz);
				}
				protected void writeText(QuickWriter writer, String text) {
					if (cdata) {
						writer.write("<![CDATA[");
						writer.write(text);
						writer.write("]]>");
					} else {
						writer.write(text);
					}
				}
			};
		}
	});

	/**
	 * 获取access_token
	 * 
	 * @param appid
	 *            凭证
	 * @param appsecret
	 *            密钥
	 * @return
	 */
	public static AccessToken getAccessToken(String appid, String appsecret) {
		AccessToken accessToken = null;

		String requestUrl = access_token_url.replace("APPOLDID", appid).replace("APPOLDSECRET", appsecret);
		JSONObject jsonObject = httpsRequest(requestUrl, "GET", null);
		// 如果请求成功
		if (null != jsonObject) {
			try {
				accessToken = new AccessToken();
				// 将获取到的凭证以及凭证的有效时间保存起来
				accessToken.setToken(jsonObject.getString("access_token"));
				accessToken.setExpiresIn(jsonObject.getInteger("expires_in"));
			} catch (JSONException e) {
				accessToken = null;
				// 获取token失败
			}
		}
		return accessToken;
	}

	/**
	 * 获取 jsapi_ticket { "errcode":0, "errmsg":"ok", "ticket":
	 * "bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA"
	 * , "expires_in":7200 }
	 * 
	 * @param access_token
	 * @return
	 */
	public static JsapiTicket getJsapiTicket(String access_token) {
		JsapiTicket jsapiTicket = null;
		String requstStr = HttpUtils.sendGet("https://api.weixin.qq.com/cgi-bin/ticket/getticket", "access_token=" + access_token + "&type=jsapi");
		JSONObject object = JSONObject.parseObject(requstStr);
		// 如果请求成功
		if (null != object) {
			try {
				jsapiTicket = new JsapiTicket();
				// 将获取到的凭证以及凭证的有效时间保存起来
				jsapiTicket.setJsapticket(object.getString("ticket"));
				jsapiTicket.setExpiresIn(object.getInteger("expires_in"));
			} catch (JSONException e) {
				jsapiTicket = null;
				// 获取ticket失败
			}
		}
		return jsapiTicket;
	}
	public static final String menu_create_url = " https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";
	/**
	 * 创建菜单
	 */
	public static int createMenu(Menu menu, String accessToken) {
		int result = 0;
		// 拼接创建菜单的url
		String url = menu_create_url.replaceAll("ACCESS_TOKEN", accessToken);
		System.out.println("wechat_url"+url);
		String jsonMenu = JSONObject.toJSON(menu).toString();
		System.out.println("wechat_jsonMenu"+jsonMenu);
		JSONObject jsonObject = httpsRequest(url, "POST", jsonMenu);
		System.out.println("wechat_result"+jsonObject);
		return result;
	}

	/**
	 * java生成随机数字和字母组合
	 * 
	 * @param length
	 *            [生成随机数的长度]
	 * @return
	 */
	public static String getCharAndNumr(int length) {
		String val = "";
		Random random = new Random();
		for (int i = 0; i < length; i++) {
			// 输出字母还是数字
			String charOrNum = random.nextInt(2) % 2 == 0 ? "char" : "num";
			// 字符串
			if ("char".equalsIgnoreCase(charOrNum)) {
				// 取得大写字母还是小写字母
				int choice = random.nextInt(2) % 2 == 0 ? 65 : 97;
				val += (char) (choice + random.nextInt(26));
			} else if ("num".equalsIgnoreCase(charOrNum)) { // 数字
				val += String.valueOf(random.nextInt(10));
			}
		}
		return val;
	}
	/**
	 * 将字节数组转换为十六进制字符串
	 * 
	 * @param byteArray
	 * @return
	 */
	private static String byteToStr(byte[] byteArray) {
		String strDigest = "";
		for (int i = 0; i < byteArray.length; i++) {
			strDigest += byteToHexStr(byteArray[i]);
		}
		return strDigest;
	}
	/**
	 * 将字节转换为十六进制字符串
	 * @param mByte
	 * @return
	 */
	private static String byteToHexStr(byte mByte) {
		char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
		char[] tempArr = new char[2];
		tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
		tempArr[1] = Digit[mByte & 0X0F];
		String s = new String(tempArr);
		return s;
	}

	private static String token = "caa";
	/*
	 * 微信服务号的TOKEN url进行验证
	 */
	public static boolean checkSignature(String signature, String timestamp, String nonce) {

		String[] arr = new String[] { token, timestamp, nonce };
		System.out.println("token   " + token);
		// 将token、timestamp、nonce三个参数进行字典序排序
		Arrays.sort(arr);
		StringBuilder content = new StringBuilder();
		for (int i = 0; i < arr.length; i++) {
			content.append(arr[i]);
		}
		MessageDigest md = null;
		String tmpStr = null;
		try {
			md = MessageDigest.getInstance("SHA-1");
			// 将三个参数字符串拼接成一个字符串进行sha1加密
			byte[] digest = md.digest(content.toString().getBytes());
			tmpStr = byteToStr(digest);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		content = null;
		// 将sha1加密后的字符串可与signature对比，标识该请求来源于微信
		return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
	}
	/**
	 * 获取openID
	 * @param request
	 * @param code
	 */
	public static JSONObject getOpenID(HttpServletRequest request, String code) {
		System.out.println("微信code:" + code + "================");
		// 通过code获取网页授权access_token
		String accesstoken = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + APPID + "&secret=" + APPSECRET + "&code=" + code + "&grant_type=authorization_code";
		JSONObject jsonObject = WechatMessageUtils.httpsRequest(accesstoken, "GET", "");
		if (jsonObject.getString("errcode") != null) {// 访问接口失败的错误信息
			System.out.println("获取openID失败");
		} else {
			System.out.println("OpenID:" + jsonObject.getString("openid") + "==================");
			System.out.println("UnionId:" + jsonObject.getString("unionid") + "==================");
			request.getSession().setAttribute("openid", jsonObject.getString("openid"));
			request.getSession().setAttribute("unionid", jsonObject.getString("unionid"));
		}
		return jsonObject;
	}

	public static void main(String[] args) throws Exception {
		System.out.println("148");

		// 创建SSLContext对象，并使用我们指定的信任管理器初始化
		TrustManager[] tm = { new MyX509TrustManager() };
		SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
		sslContext.init(null, tm, new java.security.SecureRandom());
		// 从上述SSLContext对象中得到SSLSocketFactory对象
		SSLSocketFactory ssf = sslContext.getSocketFactory();
		URL url = new URL("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wx7a5e4aa03aa9a154&secret=a07973e5cd48835328a6856da2da3f15");
		System.out.println("--url:" + url + "--=");
		HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
		httpUrlConn.setSSLSocketFactory(ssf);

		System.out.println("1");
		httpUrlConn.setDoOutput(true);
		httpUrlConn.setDoInput(true);
		httpUrlConn.setUseCaches(false);
		// 设置请求方式（GET/POST）
		httpUrlConn.setRequestMethod("GET");
		System.out.println("2");
		if ("GET".equalsIgnoreCase("GET")) {
			System.out.println("methodType:" + "GET");
			httpUrlConn.connect();
		}
		System.out.println("2.1");
	}
}
